home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 722 / 722.xpi / chrome / noscript.jar / content / noscript / IOUtil.js < prev    next >
Text File  |  2010-02-12  |  19KB  |  590 lines

  1. INCLUDE("DNS");
  2.  
  3. const IO = {
  4.   readFile: function(file, charset) {
  5.     var res;
  6.     
  7.     const is = CC["@mozilla.org/network/file-input-stream;1"]
  8.       .createInstance(CI.nsIFileInputStream );
  9.     is.init(file ,0x01, 0400, null);
  10.     const sis = CC["@mozilla.org/scriptableinputstream;1"]
  11.       .createInstance(CI.nsIScriptableInputStream);
  12.     sis.init(is);
  13.     
  14.     res = sis.read(sis.available());
  15.     is.close();
  16.     
  17.     if (charset !== null) { // use "null" if you want uncoverted data...
  18.       const unicodeConverter = CC["@mozilla.org/intl/scriptableunicodeconverter"]
  19.         .createInstance(CI.nsIScriptableUnicodeConverter);
  20.       try {
  21.         unicodeConverter.charset = charset || "UTF-8";
  22.       } catch(ex) {
  23.         unicodeConverter.charset = "UTF-8";
  24.       }
  25.       res = unicodeConverter.ConvertToUnicode(res);
  26.     }
  27.   
  28.     return res;
  29.   },
  30.   writeFile: function(file, content, charset) {
  31.     const unicodeConverter = CC["@mozilla.org/intl/scriptableunicodeconverter"]
  32.       .createInstance(CI.nsIScriptableUnicodeConverter);
  33.     try {
  34.       unicodeConverter.charset = charset || "UTF-8";
  35.     } catch(ex) {
  36.       unicodeConverter.charset = "UTF-8";
  37.     }
  38.     
  39.     content = unicodeConverter.ConvertFromUnicode(content);
  40.     const os = CC["@mozilla.org/network/file-output-stream;1"]
  41.       .createInstance(CI.nsIFileOutputStream);
  42.     os.init(file, 0x02 | 0x08 | 0x20, 0700, 0);
  43.     os.write(content, content.length);
  44.     os.close();
  45.   },
  46.   
  47.   safeWriteFile: function(file, content, charset) {
  48.     var tmp = file.clone();
  49.     var name = file.leafName;
  50.     tmp.leafName = name + ".tmp";
  51.     tmp.createUnique(CI.nsIFile.NORMAL_FILE_TYPE, file.exists() ? file.permissions : 0600);
  52.     this.writeFile(tmp, content, charset);
  53.     tmp.moveTo(file.parent, name);
  54.   }
  55. };
  56.  
  57.  
  58. function nsISupportWrapper(wrapped) {
  59.   this.wrappedJSObject = wrapped;
  60. }
  61. nsISupportWrapper.prototype = {
  62.   QueryInterface: xpcom_generateQI([CI.nsISupports])
  63. }
  64.  
  65. const IOUtil = {
  66.   asyncNetworking: true,
  67.   proxiedDNS: 0,
  68.  
  69.   attachToChannel: function(channel, key, requestInfo) {
  70.     if (channel instanceof CI.nsIWritablePropertyBag2) 
  71.       channel.setPropertyAsInterface(key, new nsISupportWrapper(requestInfo));
  72.   },
  73.   extractFromChannel: function(channel, key, preserve) {
  74.     if (channel instanceof CI.nsIPropertyBag2) {
  75.       try {
  76.         var requestInfo = channel.getPropertyAsInterface(key, CI.nsISupports);
  77.         if (requestInfo) {
  78.           if(!preserve && (channel instanceof CI.nsIWritablePropertyBag)) channel.deleteProperty(key);
  79.           return requestInfo.wrappedJSObject;
  80.         }
  81.       } catch(e) {}
  82.     }
  83.     return null;
  84.   },
  85.  
  86.   extractInternalReferrer: function(channel) {
  87.     if (channel instanceof CI.nsIPropertyBag2) try {
  88.       return channel.getPropertyAsInterface("docshell.internalReferrer", CI.nsIURL);
  89.     } catch(e) {}
  90.     return null;
  91.   },
  92.   extractInternalReferrerSpec: function(channel) {
  93.     var ref = this.extractInternalReferrer(channel);
  94.     return ref && ref.spec || null;
  95.   },
  96.   
  97.   getProxyInfo: function(channel) {
  98.     return CI.nsIProxiedChannel && (channel instanceof CI.nsIProxiedChannel) 
  99.     ? channel.proxyInfo
  100.     : Components.classes["@mozilla.org/network/protocol-proxy-service;1"]
  101.         .getService(Components.interfaces.nsIProtocolProxyService)
  102.         .resolve(channel.URI, 0);
  103.   },
  104.   
  105.   
  106.   canDoDNS: function(channel) {
  107.     if (!channel || IOS.offline) return false;
  108.     
  109.     var proxyInfo = this.getProxyInfo(channel);
  110.     switch(this.proxiedDNS) {
  111.       case 1:
  112.         return !(proxyInfo && (proxyInfo.flags & CI.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST));
  113.       case 2:
  114.         return true;
  115.       default:
  116.         return !proxyInfo || proxyInfo.type == "direct";   
  117.     }
  118.  
  119.   },
  120.   
  121.   abort: function(channel, noNetwork) {
  122.     if (noNetwork && !ChannelReplacement.supported) {
  123.       // this is for Gecko 1.1 which doesn't allow us to cancel in asyncOpen()
  124.       channel.loadFlags |= CI.nsICachingChannel.LOAD_ONLY_FROM_CACHE; 
  125.     }
  126.     channel.cancel(Components.results.NS_ERROR_ABORT);
  127.   },
  128.   
  129.   findWindow: function(channel) {
  130.     for each(var cb in [channel.notificationCallbacks,
  131.                        channel.loadGroup && channel.loadGroup.notificationCallbacks]) {
  132.       if (cb instanceof CI.nsIInterfaceRequestor) {
  133.         if (CI.nsILoadContext) try {
  134.         // For Gecko 1.9.1
  135.           return cb.getInterface(CI.nsILoadContext).associatedWindow;
  136.         } catch(e) {}
  137.         
  138.         try {
  139.           // For Gecko 1.9.0
  140.           return cb.getInterface(CI.nsIDOMWindow);
  141.         } catch(e) {}
  142.       }
  143.     }
  144.     return null;
  145.   },
  146.   
  147.   readFile: IO.readFile,
  148.   writeFile: IO.writeFile,
  149.   safeWriteFIle: IO.safeWriteFile,
  150.   
  151.   unwrapURL: function(url) {
  152.     
  153.     try {
  154.       if (!(url instanceof CI.nsIURI))
  155.         url = IOS.newURI(url, null, null);
  156.       
  157.       switch (url.scheme) {
  158.         case "view-source":
  159.           return this.unwrapURL(url.path);
  160.         case "wyciwyg":
  161.           return this.unwrapURL(url.path.replace(/^\/\/\d+\//, ""));
  162.         case "jar":
  163.           if (url instanceof CI.nsIJARURI)
  164.             return this.unwrapURL(url.JARFile);
  165.       }
  166.     }
  167.     catch (e) {}
  168.     
  169.     return url;
  170.   },
  171.   
  172.   
  173.   get _channelFlags() {
  174.     delete this._channelFlags;
  175.     var ff = {};
  176.     [CI.nsIHttpChannel, CI.nsICachingChannel].forEach(function(c) {
  177.       for (var p in c) {
  178.         if (/^[A-Z_]+$/.test(p)) ff[p] = c[p];
  179.       }
  180.     });
  181.     return this._channelFlags = ff;
  182.   },
  183.   humanFlags: function(loadFlags) {
  184.     var hf = [];
  185.     var c = this._channelFlags;
  186.     for (var p in c) {
  187.       if (loadFlags & c[p]) hf.push(p + "=" + c[p]);
  188.     }
  189.     return hf.join("\n");
  190.   },
  191.   
  192.   queryNotificationCallbacks: function(chan, iid) {
  193.     var cb;
  194.     try {
  195.       cb = chan.notificationCallbacks.getInterface(iid);
  196.       if (cb) return cb;
  197.     } catch(e) {}
  198.     
  199.     try {
  200.       return chan.loadGroup && chan.loadGroup.notificationCallbacks.getInterface(iid);
  201.     } catch(e) {}
  202.     
  203.     return null;
  204.   },
  205.   
  206.  
  207.   anonymizeURI: function(uri, cookie) {
  208.     if (uri instanceof CI.nsIURL) {
  209.       uri.query = this.anonymizeQS(uri.query, cookie);
  210.     } else return this.anonymizeURL(uri, cookie);
  211.     return uri;
  212.   },
  213.   anonymizeURL: function(url, cookie) {
  214.     var parts = url.split("?");
  215.     if (parts.length < 2) return url;
  216.     parts[1] = this.anonymizeQS(parts[1], cookie);
  217.     return parts.join("?");
  218.   },
  219.   anonymizeQS: function(qs, cookie) {
  220.     if (!qs) return qs;
  221.     if (!/[&=]/.test(qs)) return '';
  222.     
  223.     var cookieNames, hasCookies;
  224.     if ((hasCookies = !!cookie)) {
  225.       cookieNames = cookie.split(/\s*;\s*/).map(function(nv) {
  226.         return nv.split("=")[0];
  227.       })
  228.     }
  229.     
  230.     var parms = qs.split("&");
  231.     var nv, name;
  232.     for (var j = parms.length; j-- > 0;) {
  233.       nv = parms[j].split("=");
  234.       name = nv[0];
  235.       if (/(?:auth|s\w+(?:id|key)$)/.test(name) || cookie && cookieNames.indexOf(name) > -1)
  236.         parms.splice(j, 1);
  237.     }
  238.     return parms.join("&");
  239.   },
  240.   
  241.   runWhenPending: function(channel, callback) {
  242.     if (channel.isPending()) {
  243.       callback();
  244.       return false;
  245.     } else {
  246.       new LoadGroupWrapper(channel, {
  247.         addRequest: function(r, ctx) {
  248.           callback();
  249.         }
  250.       });
  251.       return true;
  252.     }
  253.   }
  254.   
  255. };
  256.  
  257. function CtxCapturingListener(tracingChannel, notify) {
  258.   this.originalListener = tracingChannel.setNewListener(this);
  259.   if (notify) this.notify = true;
  260. }
  261. CtxCapturingListener.prototype = {
  262.   originalListener: null,
  263.   originalCtx: null,
  264.   notify: false,
  265.   onDataAvailable: function(request, context, inputStream, offset, count) {
  266.     this.originalCtx = context;
  267.   },
  268.   onStartRequest: function(request, context) {
  269.     this.originalCtx = context;
  270.     if (this.notify) this.originalListener.onStartRequest(request, context);
  271.   },
  272.   onStopRequest: function(request, context, statusCode) {
  273.     this.originalCtx = context;
  274.     if (this.notify) this.originalListener.onStopRequest(request, context, statusCode);
  275.   },
  276.   QueryInterface: function (aIID) {
  277.     if (aIID.equals(CI.nsIStreamListener) ||
  278.         aIID.equals(CI.nsISupports)) {
  279.         return this;
  280.     }
  281.     throw Components.results.NS_NOINTERFACE;
  282.   }
  283. }
  284.  
  285. function ChannelReplacement(chan, newURI, newMethod) {
  286.   return this._init(chan, newURI, newMethod);
  287. }
  288.  
  289. ChannelReplacement.supported = "nsITraceableChannel" in CI;
  290.  
  291. ChannelReplacement.prototype = {
  292.   listener: null,
  293.   context: null,
  294.   _ccListener: null,
  295.   oldChannel: null,
  296.   channel: null,
  297.   window: null,
  298.   get _unsupportedError() {
  299.     return new Error("Can't replace channels without nsITraceableChannel!");
  300.   },
  301.   
  302.   _init: function(chan, newURI, newMethod) {
  303.     if (!(ChannelReplacement.supported && chan instanceof CI.nsITraceableChannel))
  304.       throw this._unsupportedError;
  305.   
  306.     newURI = newURI || chan.URI;
  307.     
  308.     var newChan = IOS.newChannelFromURI(newURI);
  309.     
  310.     
  311.     
  312.     
  313.     // porting of http://mxr.mozilla.org/mozilla-central/source/netwerk/protocol/http/src/nsHttpChannel.cpp#2750
  314.     
  315.     var loadFlags = chan.loadFlags;
  316.     if (chan.URI.schemeIs("https"))
  317.       loadFlags &= ~chan.INHIBIT_PERSISTENT_CACHING;
  318.     
  319.     
  320.     newChan.loadGroup = chan.loadGroup;
  321.     newChan.notificationCallbacks = chan.notificationCallbacks;
  322.     newChan.loadFlags = loadFlags;
  323.     
  324.     if (!(newChan instanceof CI.nsIHttpChannel))
  325.       return newChan;
  326.     
  327.     // copy headers
  328.     chan.visitRequestHeaders({
  329.       visitHeader: function(key, val) {
  330.         try {
  331.           
  332.           // we skip authorization and cache-related fields which should be automatically set
  333.           if (/^(?:Host|Cookie|Authorization)$|Cache|^If-/.test(key)) return;
  334.           
  335.           newChan.setRequestHeader(key, val, false);
  336.         } catch (e) {
  337.           dump(e + "\n");
  338.         }
  339.       }
  340.     });
  341.     
  342.     
  343.     if (!newMethod) {
  344.       if (newChan instanceof CI.nsIUploadChannel && chan instanceof CI.nsIUploadChannel && chan.uploadStream ) {
  345.         var stream = chan.uploadStream;
  346.         if (stream instanceof CI.nsISeekableStream) {
  347.           stream.seek(stream.NS_SEEK_SET, 0);
  348.         }
  349.         
  350.         try {
  351.           var ctype = chan.getRequestHeader("Content-type");
  352.           var clen = chan.getRequestHeader("Content-length");
  353.           if (ctype && clen) {
  354.             newChan.setUploadStream(stream, ctype, parseInt(clen));
  355.           }
  356.         } catch(e) {
  357.           newChan.setUploadStream(stream, '', -1);
  358.         }
  359.         
  360.         newChan.requestMethod = chan.requestMethod;
  361.       }
  362.     } else {
  363.       newChan.method = newMethod;
  364.     }
  365.     
  366.     if (chan.referrer) newChan.referrer = chan.referrer;
  367.     newChan.allowPipelining = chan.allowPipelining;
  368.     newChan.redirectionLimit = chan.redirectionLimit - 1;
  369.     if (chan instanceof CI.nsIHttpChannelInternal && newChan instanceof CI.nsIHttpChannelInternal) {
  370.       if (chan.URI == chan.documentURI) {
  371.         newChan.documentURI = newURI;
  372.       } else {
  373.         newChan.documentURI = chan.documentURI;
  374.       }
  375.     }
  376.     
  377.     if (chan instanceof CI.nsIEncodedChannel && newChan instanceof CI.nsIEncodedChannel) {
  378.       newChan.applyConversion = chan.applyConversion;
  379.     }
  380.     
  381.     // we can't transfer resume information because we can't access mStartPos and mEntityID :(
  382.     // http://mxr.mozilla.org/mozilla-central/source/netwerk/protocol/http/src/nsHttpChannel.cpp#2826
  383.     
  384.     if ("nsIApplicationCacheChannel" in CI &&
  385.       chan instanceof CI.nsIApplicationCacheChannel && newChan instanceof CI.nsIApplicationCacheChannel) {
  386.       newChan.applicationCache = chan.applicationCache;
  387.       newChan.inheritApplicationCache = chan.inheritApplicationCache;
  388.     }
  389.     
  390.     if (chan instanceof CI.nsIPropertyBag && newChan instanceof CI.nsIWritablePropertyBag) 
  391.       for (var properties = chan.enumerator, p; properties.hasMoreElements();)
  392.         if ((p = properties.getNext()) instanceof CI.nsIProperty)
  393.           newChan.setProperty(p.name, p.value);
  394.     
  395.     this.oldChannel = chan;
  396.     this.channel = newChan;
  397.     
  398.     if (chan.loadFlags & chan.LOAD_DOCUMENT_URI) {
  399.       this.window = IOUtil.findWindow(chan);
  400.     }
  401.     
  402.     return this;
  403.   },
  404.   
  405.   _onChannelRedirect: function(trueRedir) {
  406.     var oldChan = this.oldChannel;
  407.     var newChan = this.channel;
  408.     
  409.     if (trueRedir) {
  410.       if (oldChan.redirectionLimit === 0) {
  411.         oldChan.cancel(NS_ERROR_REDIRECT_LOOP);
  412.         throw NS_ERROR_REDIRECT_LOOP;
  413.       }
  414.     } else newChan.redirectionLimit += 1;
  415.     
  416.     newChan.loadFlags |= newChan.LOAD_REPLACE;
  417.     
  418.     // nsHttpHandler::OnChannelRedirect()
  419.     const CES = CI.nsIChannelEventSink;
  420.     const flags = CES.REDIRECT_INTERNAL;
  421.     CC["@mozilla.org/netwerk/global-channel-event-sink;1"].getService(CES)
  422.       .onChannelRedirect(oldChan, newChan, flags);
  423.     var ces;
  424.     for (var cess = CC['@mozilla.org/categorymanager;1'].getService(CI.nsICategoryManager)
  425.               .enumerateCategory("net-channel-event-sinks");
  426.         cess.hasMoreElements();) {
  427.       ces = cess.getNext();
  428.       if (ces instanceof CES)
  429.         ces.onChannelRedirect(oldChan, newChan, flags);
  430.     }
  431.     ces = IOUtil.queryNotificationCallbacks(oldChan, CES);
  432.     if (ces) ces.onChannelRedirect(oldChan, newChan, flags);
  433.     // ----------------------------------
  434.     
  435.     newChan.originalURI = oldChan.originalURI;
  436.     
  437.     ces =  IOUtil.queryNotificationCallbacks(oldChan, CI.nsIHttpEventSink);
  438.     if (ces) ces.onRedirect(oldChan, newChan);
  439.     
  440.   },
  441.   
  442.   replace: function(isRedir) {
  443.     
  444.     this._onChannelRedirect(isRedir);
  445.     
  446.     // dirty trick to grab listenerContext
  447.     var oldChan = this.oldChannel;
  448.     
  449.     var ccl = new CtxCapturingListener(oldChan);
  450.     
  451.     oldChan.cancel(NS_BINDING_REDIRECTED); // this works because we've been called after loadGroup->addRequest(), therefore asyncOpen() always return NS_OK
  452.     
  453.     oldChan.notificationCallbacks =
  454.         oldChan.loadGroup = null; // prevent loadGroup removal and wheel stop
  455.     
  456.     if (oldChan instanceof CI.nsIRequestObserver) {
  457.       oldChan.onStartRequest(oldChan, null);
  458.     }
  459.  
  460.     this.listener = ccl.originalListener;
  461.     this.context = ccl.originalCtx;
  462.     this._ccListener = ccl;
  463.     
  464.     return this;
  465.   },
  466.   
  467.   open: function() {
  468.     var oldChan = this.oldChannel, newChan = this.channel;
  469.  
  470.     var overlap, fail = false;
  471.     
  472.     if (!(this.window && (overlap = ABERequest.getLoadingChannel(this.window)) !== oldChan)) {
  473.       try {
  474.         if (ABE.consoleDump && this.window) {
  475.           ABE.log("Opening delayed channel: " + oldChan.name + " - (current loading channel for this window " + (overlap && overlap.name) + ")");
  476.         }
  477.  
  478.         newChan.asyncOpen(this.listener, this.context);
  479.         
  480.         // safe browsing hook
  481.         try {
  482.           CC["@mozilla.org/channelclassifier"].createInstance(CI.nsIChannelClassifier).start(newChan, true);
  483.         } catch (e) {
  484.           // may throw if host app doesn't implement url classification
  485.         }
  486.       } catch (e) {
  487.         // redirect failed: we must notify the original channel listener, so let's restore bindings
  488.         fail = true;
  489.       }
  490.     } else {
  491.       if (ABE.consoleDump) {
  492.         ABE.log("Detected double load on the same window: " + oldChan.name + " - " + (overlap && overlap.name));
  493.       }
  494.     }
  495.     
  496.     this.cancel(NS_BINDING_REDIRECTED, fail);
  497.   },
  498.   
  499.   cancel: function(status, fail) {
  500.     var oldChan = this.oldChannel, newChan = this.channel;
  501.     if (fail) {
  502.       oldChan.notificationCallbacks = newChan.notificationCallbacks;
  503.       this._ccListener.notify = true;
  504.       if (oldChan instanceof CI.nsIRequestObserver)
  505.         try {
  506.         oldChan.onStartRequest(oldChan, null);
  507.         } catch(e) {}
  508.     }
  509.     
  510.     if (oldChan instanceof CI.nsIRequestObserver)
  511.       try {  
  512.         oldChan.onStopRequest(oldChan, null, status);
  513.       } catch(e) {}
  514.     
  515.     if (newChan.loadGroup)
  516.       try {
  517.         newChan.loadGroup.removeRequest(oldChan, null, status);
  518.       } catch(e) {}
  519.  
  520.     oldChan.notificationCallbacks = null;
  521.     delete this._ccListener;
  522.     delete this.window;
  523.     delete this.oldChannel;
  524.   }
  525. }
  526.  
  527. function LoadGroupWrapper(channel, callbacks) {
  528.   this._channel = channel;
  529.   this._inner = channel.loadGroup;
  530.   this._callbacks = callbacks;
  531.   channel.loadGroup = this;
  532. }
  533. LoadGroupWrapper.prototype = {
  534.   QueryInterface: xpcom_generateQI(CI.nsISupports, CI.nsILoadGroup),
  535.   
  536.   get activeCount() {
  537.     return this._inner ? this._inner.activeCount : 0;
  538.   },
  539.   set defaultLoadRequest(v) {
  540.     return this._inner ? this._inner.defaultLoadRequest = v : v;
  541.   },
  542.   get defaultLoadRequest() {
  543.     return this._inner ? this._inner.defaultLoadRequest : null;
  544.   },
  545.   set groupObserver(v) {
  546.     return this._inner ? this._inner.groupObserver = v : v;
  547.   },
  548.   get groupObserver() {
  549.     return this._inner ? this._inner.groupObserver : null;
  550.   },
  551.   set notificationCallbacks(v) {
  552.     return this._inner ? this._inner.notificationCallbacks = v : v;
  553.   },
  554.   get notificationCallbacks() {
  555.     return this._inner ? this._inner.notificationCallbacks : null;
  556.   },
  557.   get requests() {
  558.     return this._inner ? this._inner.requests : this._emptyEnum;
  559.   },
  560.   
  561.   addRequest: function(r, ctx) {
  562.     this.detach();
  563.     if (this._inner) try {
  564.       this._inner.addRequest(r, ctx);
  565.     } catch(e) {
  566.       // addRequest may have not been implemented
  567.     }
  568.     if (r === this._channel && ("addRequest" in this._callbacks))
  569.       try {
  570.         this._callbacks.addRequest(r, ctx);
  571.       } catch (e) {}
  572.   },
  573.   removeRequest: function(r, ctx, status) {
  574.     this.detach();
  575.     if (this._inner) this._inner.removeRequest(r, ctx, status);
  576.     if (r === this._channel && ("removeRequest" in this._callbacks))
  577.       try {
  578.         this._callbacks.removeRequest(r, ctx, status);
  579.       } catch (e) {}
  580.   },
  581.   
  582.   detach: function() {
  583.     if (this._channel.loadGroup) this._channel.loadGroup = this._inner;
  584.   },
  585.   _emptyEnum: {
  586.     QueryInterface: xpcom_generateQI(CI.nsISupports, CI.nsISimpleEnumerator),
  587.     getNext: function() { return null; },
  588.     hasMoreElements: function() { return false; }
  589.   }
  590. }